<template>
  <div class="file-preview">
    <!-- 图片预览 -->
    <van-image-preview
      v-if="isImage && showPreview"
      v-model:show="showPreview"
      :images="imageList"
      :start-position="currentIndex"
      :show-index="showIndex"
      :show-indicators="showIndicators"
      :swipe-duration="swipeDuration"
      :close-on-popstate="closeOnPopstate"
      :class-name="previewClassName"
      @change="handleImageChange"
      @close="handleClose"
    >
      <template #index>
        <div class="file-preview__index">
          {{ currentIndex + 1 }} / {{ imageList.length }}
        </div>
      </template>
    </van-image-preview>

    <!-- 视频预览 -->
    <van-popup
      v-if="isVideo && showPreview"
      v-model:show="showPreview"
      position="center"
      :style="{ width: '90%', height: '60%' }"
      :close-on-click-overlay="closeOnClickOverlay"
      @close="handleClose"
    >
      <div class="file-preview__video">
        <video
          ref="videoRef"
          :src="currentFile.url"
          :poster="currentFile.poster"
          controls
          preload="metadata"
          @loadedmetadata="handleVideoLoaded"
          @error="handleVideoError"
        >
          您的浏览器不支持视频播放
        </video>
      </div>
    </van-popup>

    <!-- 音频预览 -->
    <van-popup
      v-if="isAudio && showPreview"
      v-model:show="showPreview"
      position="bottom"
      :style="{ height: '200px' }"
      :close-on-click-overlay="closeOnClickOverlay"
      @close="handleClose"
    >
      <div class="file-preview__audio">
        <div class="file-preview__audio-info">
          <van-icon name="music-o" size="48" />
          <div class="file-preview__audio-title">{{ currentFile.name }}</div>
          <div class="file-preview__audio-size">{{ formatFileSize(currentFile.size) }}</div>
        </div>
        <audio
          ref="audioRef"
          :src="currentFile.url"
          controls
          preload="metadata"
          @loadedmetadata="handleAudioLoaded"
          @error="handleAudioError"
        >
          您的浏览器不支持音频播放
        </audio>
      </div>
    </van-popup>

    <!-- PDF预览 -->
    <van-popup
      v-if="isPdf && showPreview"
      v-model:show="showPreview"
      position="center"
      :style="{ width: '95%', height: '90%' }"
      :close-on-click-overlay="closeOnClickOverlay"
      @close="handleClose"
    >
      <div class="file-preview__pdf">
        <div class="file-preview__pdf-header">
          <span class="file-preview__pdf-title">{{ currentFile.name }}</span>
          <van-button
            type="primary"
            size="small"
            @click="downloadFile"
          >
            下载
          </van-button>
        </div>
        <iframe
          :src="pdfViewerUrl"
          frameborder="0"
          class="file-preview__pdf-iframe"
        />
      </div>
    </van-popup>

    <!-- 文档预览 -->
    <van-popup
      v-if="isDocument && showPreview"
      v-model:show="showPreview"
      position="center"
      :style="{ width: '95%', height: '90%' }"
      :close-on-click-overlay="closeOnClickOverlay"
      @close="handleClose"
    >
      <div class="file-preview__document">
        <div class="file-preview__document-header">
          <span class="file-preview__document-title">{{ currentFile.name }}</span>
          <van-button
            type="primary"
            size="small"
            @click="downloadFile"
          >
            下载
          </van-button>
        </div>
        <div class="file-preview__document-content">
          <van-loading v-if="documentLoading" size="24px">加载中...</van-loading>
          <div v-else-if="documentContent" v-html="documentContent" />
          <van-empty v-else description="无法预览此文档" />
        </div>
      </div>
    </van-popup>

    <!-- 其他文件类型 -->
    <van-popup
      v-if="isOther && showPreview"
      v-model:show="showPreview"
      position="center"
      :style="{ width: '80%' }"
      :close-on-click-overlay="closeOnClickOverlay"
      @close="handleClose"
    >
      <div class="file-preview__other">
        <div class="file-preview__other-icon">
          <van-icon :name="getFileIcon(currentFile.type)" size="64" />
        </div>
        <div class="file-preview__other-info">
          <div class="file-preview__other-name">{{ currentFile.name }}</div>
          <div class="file-preview__other-size">{{ formatFileSize(currentFile.size) }}</div>
          <div class="file-preview__other-type">{{ currentFile.type || '未知类型' }}</div>
        </div>
        <div class="file-preview__other-actions">
          <van-button
            type="primary"
            block
            @click="downloadFile"
          >
            下载文件
          </van-button>
        </div>
      </div>
    </van-popup>
  </div>
</template>

<script>
import { ref, computed, watch, defineComponent } from 'vue'
import { formatFileSize } from '@/utils/fileObs'

export default defineComponent({
  name: 'FilePreview',
  props: {
    /**
     * 是否显示预览
     */
    modelValue: {
      type: Boolean,
      default: false
    },
    /**
     * 文件列表
     */
    files: {
      type: Array,
      default: () => []
    },
    /**
     * 当前文件索引
     */
    currentIndex: {
      type: Number,
      default: 0
    },
    /**
     * 是否显示索引
     */
    showIndex: {
      type: Boolean,
      default: true
    },
    /**
     * 是否显示指示器
     */
    showIndicators: {
      type: Boolean,
      default: false
    },
    /**
     * 切换动画时长
     */
    swipeDuration: {
      type: Number,
      default: 300
    },
    /**
     * 是否在页面回退时自动关闭
     */
    closeOnPopstate: {
      type: Boolean,
      default: true
    },
    /**
     * 是否点击遮罩关闭
     */
    closeOnClickOverlay: {
      type: Boolean,
      default: true
    },
    /**
     * 自定义类名
     */
    previewClassName: {
      type: String,
      default: ''
    },
    /**
     * PDF查看器URL
     */
    pdfViewerUrl: {
      type: String,
      default: ''
    }
  },
  emits: ['update:modelValue', 'change', 'close', 'download'],
  setup(props, { emit }) {
    const videoRef = ref(null)
    const audioRef = ref(null)
    const documentLoading = ref(false)
    const documentContent = ref('')

    /**
     * 显示预览状态
     */
    const showPreview = computed({
      get: () => props.modelValue,
      set: (value) => emit('update:modelValue', value)
    })

    /**
     * 当前文件
     */
    const currentFile = computed(() => {
      return props.files[props.currentIndex] || {}
    })

    /**
     * 图片列表
     */
    const imageList = computed(() => {
      return props.files
        .filter(file => isImageFile(file.type))
        .map(file => file.url)
    })

    /**
     * 是否为图片
     */
    const isImage = computed(() => {
      return isImageFile(currentFile.value.type)
    })

    /**
     * 是否为视频
     */
    const isVideo = computed(() => {
      return isVideoFile(currentFile.value.type)
    })

    /**
     * 是否为音频
     */
    const isAudio = computed(() => {
      return isAudioFile(currentFile.value.type)
    })

    /**
     * 是否为PDF
     */
    const isPdf = computed(() => {
      return isPdfFile(currentFile.value.type)
    })

    /**
     * 是否为文档
     */
    const isDocument = computed(() => {
      return isDocumentFile(currentFile.value.type)
    })

    /**
     * 是否为其他类型
     */
    const isOther = computed(() => {
      return !isImage.value && !isVideo.value && !isAudio.value && !isPdf.value && !isDocument.value
    })

    /**
     * PDF查看器URL
     */
    const pdfViewerUrl = computed(() => {
      if (props.pdfViewerUrl) {
        return `${props.pdfViewerUrl}?file=${encodeURIComponent(currentFile.value.url)}`
      }
      return currentFile.value.url
    })

    /**
     * 判断是否为图片文件
     */
    const isImageFile = (type) => {
      const imageTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']
      return imageTypes.includes(type)
    }

    /**
     * 判断是否为视频文件
     */
    const isVideoFile = (type) => {
      const videoTypes = ['video/mp4', 'video/webm', 'video/ogg', 'video/avi', 'video/mov']
      return videoTypes.includes(type)
    }

    /**
     * 判断是否为音频文件
     */
    const isAudioFile = (type) => {
      const audioTypes = ['audio/mp3', 'audio/wav', 'audio/ogg', 'audio/aac', 'audio/flac']
      return audioTypes.includes(type)
    }

    /**
     * 判断是否为PDF文件
     */
    const isPdfFile = (type) => {
      return type === 'application/pdf'
    }

    /**
     * 判断是否为文档文件
     */
    const isDocumentFile = (type) => {
      const documentTypes = [
        'application/msword',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'application/vnd.ms-excel',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'application/vnd.ms-powerpoint',
        'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        'text/plain',
        'text/html',
        'text/css',
        'text/javascript',
        'application/json'
      ]
      return documentTypes.includes(type)
    }

    /**
     * 获取文件图标
     */
    const getFileIcon = (type) => {
      const iconMap = {
        'application/pdf': 'description',
        'application/msword': 'description',
        'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'description',
        'application/vnd.ms-excel': 'description',
        'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'description',
        'application/vnd.ms-powerpoint': 'description',
        'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'description',
        'application/zip': 'zip',
        'application/x-rar-compressed': 'zip',
        'application/x-7z-compressed': 'zip',
        'text/plain': 'description',
        'text/html': 'description',
        'text/css': 'description',
        'text/javascript': 'description',
        'application/json': 'description'
      }
      return iconMap[type] || 'description'
    }

    /**
     * 图片切换处理
     */
    const handleImageChange = (index) => {
      emit('change', index)
    }

    /**
     * 关闭处理
     */
    const handleClose = () => {
      emit('close')
    }

    /**
     * 视频加载完成处理
     */
    const handleVideoLoaded = () => {
      console.log('视频加载完成')
    }

    /**
     * 视频加载错误处理
     */
    const handleVideoError = () => {
      console.error('视频加载失败')
    }

    /**
     * 音频加载完成处理
     */
    const handleAudioLoaded = () => {
      console.log('音频加载完成')
    }

    /**
     * 音频加载错误处理
     */
    const handleAudioError = () => {
      console.error('音频加载失败')
    }

    /**
     * 下载文件
     */
    const downloadFile = () => {
      emit('download', currentFile.value)
    }

    /**
     * 加载文档内容
     */
    const loadDocumentContent = async () => {
      if (!isDocument.value) return

      documentLoading.value = true
      try {
        const response = await fetch(currentFile.value.url)
        const text = await response.text()
        
        if (currentFile.value.type === 'text/html') {
          documentContent.value = text
        } else {
          documentContent.value = `<pre>${text}</pre>`
        }
      } catch (error) {
        console.error('文档加载失败:', error)
        documentContent.value = ''
      } finally {
        documentLoading.value = false
      }
    }

    /**
     * 监听当前文件变化
     */
    watch(
      () => [currentFile.value, showPreview.value],
      () => {
        if (showPreview.value && isDocument.value) {
          loadDocumentContent()
        }
      },
      { immediate: true }
    )

    return {
      videoRef,
      audioRef,
      documentLoading,
      documentContent,
      showPreview,
      currentFile,
      imageList,
      isImage,
      isVideo,
      isAudio,
      isPdf,
      isDocument,
      isOther,
      pdfViewerUrl,
      getFileIcon,
      handleImageChange,
      handleClose,
      handleVideoLoaded,
      handleVideoError,
      handleAudioLoaded,
      handleAudioError,
      downloadFile,
      formatFileSize
    }
  }
})
</script>

<style lang="scss" scoped>
.file-preview {
  &__index {
    position: absolute;
    top: 20px;
    left: 50%;
    transform: translateX(-50%);
    padding: 4px 12px;
    background-color: rgba(0, 0, 0, 0.7);
    color: #fff;
    border-radius: 12px;
    font-size: 14px;
    z-index: 1;
  }

  &__video {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: #000;

    video {
      width: 100%;
      height: 100%;
      object-fit: contain;
    }
  }

  &__audio {
    padding: 20px;
    text-align: center;

    &-info {
      margin-bottom: 20px;
    }

    &-title {
      font-size: 16px;
      font-weight: 600;
      color: #323233;
      margin: 12px 0 8px;
    }

    &-size {
      font-size: 14px;
      color: #646566;
    }

    audio {
      width: 100%;
    }
  }

  &__pdf {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;

    &-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px;
      border-bottom: 1px solid #ebedf0;
      background-color: #f7f8fa;
    }

    &-title {
      font-size: 16px;
      font-weight: 600;
      color: #323233;
      flex: 1;
      margin-right: 16px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    &-iframe {
      flex: 1;
      width: 100%;
      border: none;
    }
  }

  &__document {
    width: 100%;
    height: 100%;
    display: flex;
    flex-direction: column;

    &-header {
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 16px;
      border-bottom: 1px solid #ebedf0;
      background-color: #f7f8fa;
    }

    &-title {
      font-size: 16px;
      font-weight: 600;
      color: #323233;
      flex: 1;
      margin-right: 16px;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }

    &-content {
      flex: 1;
      padding: 16px;
      overflow: auto;
      background-color: #fff;

      pre {
        white-space: pre-wrap;
        word-wrap: break-word;
        font-family: 'Courier New', monospace;
        font-size: 14px;
        line-height: 1.5;
        color: #323233;
      }
    }
  }

  &__other {
    padding: 32px 24px;
    text-align: center;

    &-icon {
      margin-bottom: 16px;
      color: #646566;
    }

    &-info {
      margin-bottom: 24px;
    }

    &-name {
      font-size: 16px;
      font-weight: 600;
      color: #323233;
      margin-bottom: 8px;
      word-break: break-all;
    }

    &-size {
      font-size: 14px;
      color: #646566;
      margin-bottom: 4px;
    }

    &-type {
      font-size: 12px;
      color: #969799;
    }

    &-actions {
      .van-button {
        min-width: 120px;
      }
    }
  }
}
</style>